#ifndef CRC32_H
#define CRC32_H

#include <cstdio>
#include <string>
namespace num
{


#define CRC32_POLY	0x04c11db7 

/** 
 * CRC32 class:
 * \brief   Generates a Cyclic Redundancy Checksum (CRC) from a byte* buffer
 *          essentially a tool to generate 32 bit "unique" numbers for strings and files
 */
class CRC32
{
public:
    /**
     * Singleton accessor
     */
    static CRC32&   Instance();

    
    /**
     * Calculate CRC32 for a buffer
     * @param       buf     pointer to buffer of chars
     * @param       len     number of chars to read from buffer
     * @return              CRC32 number from buffer
     */
    unsigned long	crc32_calc(const char *buf, unsigned int len);		// we want to be able to access strings in addition to files

    /**
     * Calculate CRC32 for a \0 terminated string
     * Create simplified interface for standard strings
     * @param       _Str        buffer to convert
     * @param       _UpperCase  should we uppercase the string ?
     * @return                  CRC32 number from buffer
     */
    unsigned long	StrCRC(const char * _Str, bool _UpperCase = true);
	unsigned long	StrCRC(const std::string& _Str, bool _UpperCase = true);

    /**
     * Calculate CRC32 for a file
     * @param       src        file* to read
     */
    //unsigned long	calculate(FILE *src);

    /// accessors
	unsigned long	get(void);

	static unsigned long		FastHash(const std::string& Str, bool	ToUppr = true);
	static unsigned long		FastHash(unsigned char*	DataA, unsigned int Size);
private:
	unsigned long	*crc32_table;           // lookup table
	char            *crc32_filebuffer;      // internal buffer for reading files
	unsigned long	crc;	                // last crc


    /**
     *	Swap bit 0 for bit 7, bit 1 for bit 6, etc.
     */
	unsigned long	reflect(unsigned long ref, char ch);

    /**
     *	Initialize data and buffer
     */
	void			crc32_init(void);

    CRC32(void);
	~CRC32(void);
    /// Not implemented to prevent copying
    CRC32( const CRC32 & );     
    CRC32& operator=( const CRC32 & );

};

} // namespace num

#endif